package utils;

import static com.qb.devserv.FactoryActivity.fActivity;
import static com.qb.devserv.MainActivity.mActivity;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.widget.Toast;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.KeyManagementException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import utils.DevActionUtil;
import utils.DevInfoUtil;
import utils.MyUtil;

public class MqttUtil {
    private String MQTT_HOST;
    private String MQTT_TOPIC;
    private int MQTT_GOS = 0;
    private String clientId;
    private String userName;
    private String passWord;
    final private String DEV_ID = MyUtil.getDevId();
    private String DEV_SN = DevInfoUtil.getSN();
    Context mqttCtx;
    Boolean reConnect = true;

    MqttAndroidClient mqttAndroidClient;
    private boolean isSubscribed = false;

    SharedPreferences SP;

    public void init(Context ctx) {
        mqttCtx = ctx;
        SP = ctx.getSharedPreferences("dev_mgt_setting", ctx.MODE_PRIVATE);
        MQTT_GOS = 0;

        //MQTT_HOST = "ssl://192.168.6.95:8883";
        MQTT_HOST = "ssl://www.androidgmt.com:8883";
        //MQTT_HOST = "tcp://www.androidgmt.com:1883";
        MQTT_TOPIC = "AndroidGmtService/Execute/";
        deviceUpline();
    }

    public void deviceUpline() {
        userName = "ea0s1d3e2342d68f3c3dd1312";
        passWord = "";
        mqttConnect("deviceUpline", null);
    }

    public void deviceBind(JSONObject d) {
        userName = "AndroidGmt@00000000000";
        passWord = "*********************";
        mqttConnect("DEVICE_BIND_ACTION", d);
    }

    public void mqttConnect(String flag, JSONObject data) {
        clientId = userName + "@" + DEV_SN + "|" + "device_server";

        MyUtil.showLog("mqtt MQTT_HOST", MQTT_HOST);
        MyUtil.showLog("mqtt MQTT_TOPIC", MQTT_TOPIC);
        MyUtil.showLog("mqtt userName", userName);
        MyUtil.showLog("mqtt clientId", clientId);

        /* 创建MqttConnectOptions对象，并配置username和password。 */
        MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setUserName(userName.equals("") ? null : userName);
        String psw = passWord.equals("") ? "passWord" : passWord;
        mqttConnectOptions.setPassword(psw.toCharArray());
        MyUtil.showLog("reConnect", reConnect);
//        reConnect = false;
        mqttConnectOptions.setAutomaticReconnect(reConnect); // 设置自动重连
        mqttConnectOptions.setKeepAliveInterval(60);
        mqttConnectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);

//        if (MQTT_HOST.contains("ssl://")) {
//            try {
//                InputStream fis = mqttCtx.getResources().openRawResource(R.raw.cert);
//                mqttConnectOptions.setSocketFactory(getSingleSocketFactory(fis));
//            } catch (Exception e) {
//                Toast.makeText(mqttCtx, "SSL认证失败，" + e.getMessage(), Toast.LENGTH_LONG).show();
//                e.printStackTrace();
//            }
//        }
        /* 创建MqttAndroidClient对象，并设置回调接口。 */
        mqttAndroidClient = new MqttAndroidClient(mqttCtx.getApplicationContext(), MQTT_HOST, clientId);
        mqttAndroidClient.setCallback(new MqttCallback() {
            @Override
            public void connectionLost(Throwable cause) {
                MyUtil.showLog("MqttUtil connection Lost " + new Date(), "");
                mqttStatusMonitor("服务器连接失败");
            }

            @Override
            public void messageArrived(String topic, MqttMessage message) throws Exception {
                String rMsg = new String(message.getPayload());
                onMsg(topic, rMsg);
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken token) {
                MyUtil.showLog("MqttUtil deliveryComplete", "");
            }
        });

        /* 建立MQTT连接。 */
        try {
            mqttAndroidClient.connect(mqttConnectOptions, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    MyUtil.showLog("MqttUtil connect succeed " + new Date(), asyncActionToken);
                    MyUtil.showNotifaction(mqttCtx, 10086, "服务正在运行", MyUtil.formatDateTime(new Date()) + "服务器连接成功", 0, "");
                    //subscribeTopic(MQTT_TOPIC,true);
                    if (flag.equals("DEVICE_BIND_ACTION")) {
                        sendMsg("DEVICE_BIND_ACTION", data);
                    }
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    MyUtil.showLog("MqttUtil connect failed", exception);
                    mqttStatusMonitor(exception.getMessage());
                }
            });
        } catch (MqttException e) {
            mqttStatusMonitor("MQTT连接失败，" + e.getMessage());
            e.printStackTrace();
        }
    }

    //主动关闭mqtt
    public void close() {
        try {
            mqttAndroidClient.disconnect();
            reConnect = false;
        } catch (MqttException e) {
            mqttStatusMonitor("MQTT关闭失败，" + e.getMessage());
            e.printStackTrace();
        }
    }

    // 订阅主题
    public void subscribeTopic(String topic, Boolean isFirst) {
        MyUtil.showLog("MqttUtil subscribed isFirst=" + isFirst, "");
        try {
            mqttAndroidClient.subscribe("", MQTT_GOS, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    MyUtil.showLog("MqttUtil subscribed succeed", "");
                    isSubscribed = true;
                    if (isFirst) {
                        //publishMessage(topic,DEV_ID+"连接成功"+new Date());
                        //publishMessage(MQTT_TOPIC+"/DevQuery/Online",DEV_SN);
                        //publishMessage(topic+clientId,"我的序列号是"+DEV_SN);
                    }
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    MyUtil.showLog("MqttUtil subscribed failed", exception);
                    isSubscribed = false;
                }
            });

        } catch (MqttException e) {
            MyUtil.showLog("MqttUtil subscribed error", e.getMessage());
            Toast.makeText(mqttCtx, "MQTT订阅失败，" + e.getMessage(), Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }

    // 取消订阅
    public void unSubscribeTopic(String topic) {
        try {
            mqttAndroidClient.unsubscribe(topic, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    MyUtil.showLog("MqttUtil unsubscribed succeed", "");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    MyUtil.showLog("MqttUtil unsubscribed failed", exception);
                }
            });

        } catch (MqttException e) {
            MyUtil.showLog("MqttUtil unsubscribed error", e.getMessage());
            Toast.makeText(mqttCtx, "MQTT取消订阅失败，" + e.getMessage(), Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }

    // 发布主题
    public void publishMessage(String topic, String msg) {
        MyUtil.showLog(clientId + " publishMessage", msg);
        try {
            MyUtil.showLog("MqttUtil publishMessage isConnected=" + mqttAndroidClient.isConnected(), "");
            if (!mqttAndroidClient.isConnected()) mqttAndroidClient.connect();
            MyUtil.showLog("MqttUtil publishMessage isSubscribed=" + isSubscribed, "");
            //if (!isSubscribed) mqttStatusMonitor("未定义");

            MqttMessage m = new MqttMessage();
            m.setRetained(false);
            m.setPayload(msg.getBytes());
            m.setQos(MQTT_GOS);
            mqttAndroidClient.publish(topic, m, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    MyUtil.showLog("MqttUtil publish succeed", "");
                    //MyUtil.showNotifaction(mqttCtx,10086,"服务正在运行","",0,"");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    MyUtil.showLog("MqttUtil publish failed", exception);
                }
            });
        } catch (MqttException e) {
            MyUtil.showLog("MqttUtil publish error", e.getMessage());
            Toast.makeText(mqttCtx, "MQTT发布主题失败，" + e.getMessage(), Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }

    // mqtt状态监控
    private Timer mTimer;
    private TimerTask mTimerTask;

    private void mqttStatusMonitor(String err) {
        if (!reConnect) return;
        isSubscribed = false;
        if (mTimer != null) mTimer.cancel();
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() {
                //MyUtil.showLog("mqttStatusMonitor isSubscribed="+isSubscribed,new Date());
                boolean netStatus = MyUtil.isConnectIsNormal(mqttCtx);
                MyUtil.showLog("mqttStatusMonitor netStatus=" + netStatus, "");
                boolean mqttStatus = mqttAndroidClient.isConnected();
                MyUtil.showLog(clientId + " mqttStatus=" + mqttStatus, "");
                if (netStatus && mqttStatus) {
                    mTimer.cancel();
                    MyUtil.showNotifaction(mqttCtx, 10086, "服务正在运行", MyUtil.formatDateTime(new Date()) + "服务器连接成功", 0, "");
                    /*if (isSubscribed) {
                        mTimer.cancel();
                        publishMessage(MQTT_TOPIC,DEV_ID+"复活了");
                    } else {
                        subscribeTopic(MQTT_TOPIC,false);
                    }*/
                } else {
                    MyUtil.showNotifaction(mqttCtx, 10086, err, MyUtil.formatDateTime(new Date()) + "正在重新连接服务器…", 0, "");

                }
            }
        };
        mTimer.schedule(mTimerTask, 1000, 10 * 1000);
    }

    // ssl 单向认证
    private SSLSocketFactory getSingleSocketFactory(InputStream fis) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        X509Certificate caCert = null;
        BufferedInputStream bis = new BufferedInputStream(fis);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        while (bis.available() > 0) {
            caCert = (X509Certificate) cf.generateCertificate(bis);
        }
        KeyStore caKs = KeyStore.getInstance(KeyStore.getDefaultType());
        caKs.load(null, null);
        caKs.setCertificateEntry("ca-certificate", caCert);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(caKs);
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(null, tmf.getTrustManagers(), null);
        return sslContext.getSocketFactory();
    }

    /*
     * 业务函数
     * */
    // 发送指令
    public void sendMsg(String f, JSONObject d) {
        MyUtil.showLog("mqtt sendMsg:" + f, d);
        JSONObject p = new JSONObject();
        try {
            p.put("clientId", clientId);
            p.put("userName", userName);
            if (f.equals("DEVICE_BIND")) deviceBind(d);
            if (f.equals("DEVICE_BIND_ACTION")) deviceBindAction(120, p, d);
            if (f.equals("QRY_DEVICE_MODEL")) deviceModelQry(100164, p, d);
            if (f.equals("DEVICE_DETAIL")) deviceDetailUpload(100010, p, d);
        } catch (JSONException e) {
            Toast.makeText(mqttCtx, "MQTT信息发布失败，" + e.getMessage(), Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }

    // 接收指令
    private void onMsg(String t, String m) {
        String s = "topic: " + t + ", msg: " + m;
        MyUtil.showLog("MqttUtil messageArrived " + new Date(), s);
        try {
            JSONObject mo = new JSONObject(m);
//            MyUtil.showLog("message object",mo);
            JSONObject d = mo.getJSONObject("data");
            if (mo.getInt("msgType") == 35) {
                if (d.getInt("returnCode") == 10000) {
                    MyUtil.showLog("message object", d);
                    JSONArray da = d.getJSONArray("data");
                    JSONObject data0 = da.getJSONObject(0);
                    JSONObject md = new JSONObject();
                    md.put("id",data0.getString("equipment_model_id"));
                    sendMsg("QRY_DEVICE_MODEL",md);
                    mActivity.init("DEVICE_INIT");
                } else if (d.getInt("returnCode") == 50001 && d.getString("message").equals("终端不存在!")) {
                    close();
                    mActivity.init("DEVICE_BIND");
                } else {
                    Toast.makeText(mqttCtx, d.getString("message"), Toast.LENGTH_LONG).show();
                }
            } else {
                if (d.getInt("returnCode") == 10000) {
                    int mt = mo.getInt("msgType");
                    if (mt == 120) {
                        close();
                        fActivity.finish();
                        deviceUpline();
                    }
                    if (mt == 100164) {
                        getRomVersion(mo);
                    }
                    if (mt == 90020) {
                        deviceAction("update", mo);
                    }
                    if (mt == 90021) {
                        deviceAction("factory", mo);
                    }
                    if (mt == 90022) {
                        deviceAction("powerdown", mo);
                    }
                    if (mt == 90023) {
                        deviceAction("reset", mo);
                    }
                    if (mt == 90024) {
                        deviceAction("animation", mo);
                    }
                    if (mt == 50032) {
                        deviceAction("install", mo);
                    }
                    if (mt == 50033) {
                        deviceAction("uninstall", mo);
                    }
                    if (mt == 50034) {
                        deviceAction("autorun", mo);
                    }
                } else {
                    String msg = d.getString("message");
                    Toast.makeText(mqttCtx, msg, Toast.LENGTH_LONG).show();
                }
            }
        } catch (JSONException e) {
            Toast.makeText(mqttCtx, "MQTT信息接收失败，" + e.getMessage(), Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }

    /*
     * mqtt发送业务代码
     * */
    // 创建设备记录绑定设备序列号和主板序列号
    private void deviceBindAction(int msgType, JSONObject p, JSONObject data) throws JSONException {
        String t = MQTT_TOPIC + msgType;
        p.put("msgType", msgType);
        JSONObject device = new JSONObject();
        device.put("equipment", data.toString());
        p.put("message", device);
        publishMessage(t, p.toString());
    }

    // 按id查询设备型号固件信息
    private void deviceModelQry(int msgType, JSONObject p, JSONObject data) throws JSONException {
        String t = MQTT_TOPIC + msgType;
        p.put("msgType", msgType);
        p.put("message", data);
        publishMessage(t, p.toString());
    }

    // 上传设备明细
    private void deviceDetailUpload(int msgType, JSONObject p, JSONObject data) throws JSONException {
        String t = MQTT_TOPIC + msgType;
        p.put("msgType", msgType);
        JSONObject pd = new JSONObject();
        pd.put("board_sn", DEV_SN);
        pd.put("setups", data.getJSONArray("setups").toString());
        pd.put("installed_apps", data.getJSONArray("installed_apps").toString());
        String romVersion = SP.getString("ROM_VERSION","");
        if (!MyUtil.isNull(romVersion)) pd.put("current_version",romVersion);
        p.put("message", pd);
        publishMessage(t, p.toString());
    }

    /*
     * mqtt接收业务代码
     * */
    // 判断当前系统固件版本
    private void getRomVersion(JSONObject mo) {
        MyUtil.showLog("getRomVersion", mo);
        try {
            JSONObject d = mo.getJSONObject("data").getJSONArray("data").getJSONObject(0);
            JSONArray roms = d.getJSONObject("firmware").getJSONArray("edition_infos");
            String romId = SystemPropertiesReflection.get("ro.build.display.id");
            String romVersion = "";
            for (int i=0;i<roms.length();i++) {
                JSONObject o = roms.getJSONObject(i);
                MyUtil.showLog("getRomVersion", o);
                if (romId.contains(o.getString("edition"))) {
                    romVersion = o.getString("version");
                }
            }
            SharedPreferences.Editor edit = SP.edit();
            edit.putString("ROM_VERSION", romVersion);
            edit.apply();
        } catch (Exception e) {
            Toast.makeText(mqttCtx, "终端设备固件版本信息获取失败", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
        mActivity.upLoadDevDetail();
    }
    // 设备接收指令并执行固件升级、关机重启、应用安装卸载自启动
    private void deviceAction(String f, JSONObject mo) {
        MyUtil.showLog("deviceAction flag=" + f, mo);
        try {
            JSONObject m = mo.getJSONObject("message");
            String sns = m.getString("equipment_board_sns");
            MyUtil.showLog("deviceAction sn=" + DEV_SN, sns);
            if (!sns.contains(DEV_SN)) {
                Toast.makeText(mqttCtx, "主板序列号不匹配，指令终止", Toast.LENGTH_LONG).show();
                return;
            }
            JSONObject d = mo.getJSONObject("data");
            JSONArray da = d.getJSONArray("data");
            JSONObject d0 = null,d1 = null;
            Boolean isConfirm = true;
            if (f.equals("animation")) {
                DevActionUtil.downloadAnimation(mqttCtx);
            } else {
                d0 = new JSONObject(da.get(0).toString());
                d1 = new JSONObject(da.get(1).toString());
                if (!f.equals("autorun")) isConfirm = d1.getBoolean("isConfirm");
            }
            if (f.equals("update")) {
                String nVersion = d0.getString("version");
                String url = d0.getString("url");
                String cVersion = SP.getString("ROM_VERSION", "");
                if (cVersion.equals(nVersion)) {
                    Toast.makeText(mqttCtx, "当前系统固件已是最新版本，无需升级", Toast.LENGTH_LONG).show();
                } else if (MyUtil.isNull(url)) {
                    Toast.makeText(mqttCtx, "无效的系统固件下载URL", Toast.LENGTH_LONG).show();
                } else {
                    DevActionUtil.updateDownload(mqttCtx, f, url, isConfirm);
                }
            }
            if (f.equals("factory")) {
                DevActionUtil.reFactory(mqttCtx, f, isConfirm);
            }
            if (f.equals("powerdown")) {
                DevActionUtil.powerDown(mqttCtx, f, isConfirm);
            }
            if (f.equals("reset")) {
                DevActionUtil.reSet(mqttCtx, f, isConfirm);
            }
            if (f.equals("install")) {
                String name = d0.getString("name");;
                String url = d0.getString("url");;
                DevActionUtil.appAction(mqttCtx, f, name, url, isConfirm);
            }
            if (f.equals("uninstall")) {
                String pkname = d0.getString("package_name");;
                DevActionUtil.appAction(mqttCtx, f, pkname, null, isConfirm);
            }
            if (f.equals("autorun")) {
                String pkname = d0.getString("package_name");;
                Boolean isAutoRun = d1.getBoolean("isAutoRun");;
                DevActionUtil.appAction(mqttCtx, f, pkname, null, isAutoRun);
            }
        } catch (JSONException e) {
            Toast.makeText(mqttCtx, "来自终端管理平台的"+f+"指令执行失败", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
    }
}